package com.study.netty.server.service;

import cn.hutool.core.thread.ThreadUtil;

import com.study.netty.server.config.NettyProperty;
import com.study.netty.server.handle.FixedLengthFrameEncoder;
import com.study.netty.server.handle.ServerInboundHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

/**
 * @ClassName NettyServer
 * @Description netty启动类
 * @Author csc
 * @Date 2023/5/16 10:45
 * @Version 1.0
 */
@Slf4j
@Component
public class NettyServer {

    private Channel channel;

    // boss事件轮询线程组，处理连接事件
    private final EventLoopGroup bossGroup = new NioEventLoopGroup();
    // worker事件轮询线程组，用于数据处理
    private final EventLoopGroup workerGroup = new NioEventLoopGroup();


    @Autowired
    private ServerInboundHandler serverInboundHandler;

    @Autowired
    private NettyProperty nettyProperty;

    public NettyServer(){
        ThreadUtil.execute(()->{
            run();
        });
    }


    /**
     * 开启Netty服务
     */
    public void run() {
        try {
            log.info("开始启动netty");
            // 启动类
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            // 设置参数，组配置
            serverBootstrap.group(bossGroup, workerGroup)
                    // 指定channel
                    .channel(NioServerSocketChannel.class)

                    //服务端接受连接的队列长度，如果队列已满，客户端连接将被拒绝
                    .option(ChannelOption.SO_BACKLOG, nettyProperty.getSo())
                    // 允许重复使用本地地址和端口，连接关闭后，可以立即重用端口
                    .option(ChannelOption.SO_REUSEADDR, true)
                    // 设置TCP长连接，TCP会主动探测空闲连接的有效性
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    // 禁用Nagle算法，小数据时可以即时传输
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    // 发送缓冲区大小
                    .childOption(ChannelOption.SO_SNDBUF, 256 * 1024)
                    // 接收缓冲区大小
                    .childOption(ChannelOption.SO_RCVBUF, 256 * 1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            // 增加解码器，解决Tcp服务服务器粘包/拆包的问题
                            ch.pipeline().addLast(new FixedLengthFrameEncoder(60));
                            //Netty服务端channel初始化
                            ch.pipeline().addLast(serverInboundHandler);
                        }
                    });


            // 绑定端口，开始接收进来的连接
            ChannelFuture future = serverBootstrap.bind(nettyProperty.getPort()).sync();
            future.channel().closeFuture().sync();
            if (future.isSuccess()) {
                log.info("Netty服务端启动!! 端口:[{}]", nettyProperty.getPort());
            }
            channel = future.channel();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("Netty服务端启动异常!! error:{}", e.getMessage());
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    @PreDestroy
    private void destroy() {
        if (channel != null) {
            channel.close();
        }
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
        log.warn("Netty服务关闭!!");
    }



}
